package cn.jetpiece.cloud.common.app.modular.message.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.jetpiece.cloud.common.api.message.AnnouncementApi;
import cn.jetpiece.cloud.common.api.message.model.params.CreateAnnouncementParam;
import cn.jetpiece.cloud.common.api.message.model.params.UpdateAnnouncementParam;
import cn.jetpiece.cloud.common.api.message.model.query.AnnouncementQuery;
import cn.jetpiece.cloud.common.api.message.model.result.AnnouncementMessageResult;
import cn.jetpiece.cloud.common.api.message.model.result.AnnouncementResult;
import cn.jetpiece.cloud.common.api.message.constans.MessageConstant;
import cn.jetpiece.cloud.common.app.modular.message.entity.Announcement;
import cn.jetpiece.cloud.common.app.modular.message.service.IAnnouncementSendService;
import cn.jetpiece.cloud.common.app.modular.message.service.IAnnouncementService;
import cn.jetpiece.cloud.common.app.modular.message.wrapper.AnnouncementWrapper;
import cn.jetpiece.cloud.common.app.modular.websocket.manager.WebSocket;
import cn.jetpiece.cloud.core.context.LoginUserContext;
import cn.jetpiece.cloud.core.page.PageFactory;
import cn.jetpiece.cloud.core.query.QueryGenerator;
import cn.jetpiece.cloud.core.util.HttpContext;
import cn.jetpiece.cloud.core.util.ResultWrapperUtil;
import cn.jetpiece.cloud.model.contants.CommonConstant;
import cn.jetpiece.cloud.model.contants.CommonSendStatus;
import cn.jetpiece.cloud.model.contants.WebsocketConst;
import cn.jetpiece.cloud.model.model.LoginUser;
import cn.jetpiece.cloud.model.page.PageResult;
import cn.jetpiece.cloud.model.response.Result;
import cn.jetpiece.cloud.model.util.XSSUtils;
import cn.jetpiece.cloud.starter.app.modular.base.controller.BaseController;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;
import java.util.List;

/**
 * 系统通告表
 *
 * @author jetpiece
 * @since 2022-11-16
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class AnnouncementController extends BaseController<Announcement, IAnnouncementService> implements AnnouncementApi {
    private final IAnnouncementService announcementService;
    private final IAnnouncementSendService announcementSendService;
    private final WebSocket webSocket;

    @Override
    public Result<String> add(CreateAnnouncementParam param) {
        try {
            param.setTitle(XSSUtils.striptXSS(param.getTitle()));
            if (param.getTenantId() == null) {
                param.setTenantId(LoginUserContext.getInstance().getRelTenantId());
            }
            if (StrUtil.isBlank(param.getSendStatus())) {
                param.setSendStatus(CommonSendStatus.UNPUBLISHED_STATUS_0);
            }
            Announcement announcement = BeanUtil.toBean(param, Announcement.class);
            boolean result = announcementService.saveAnnouncement(announcement);
            if (result) {
                /* 新增时状态为发布的则自动发布 */
                if (announcement.getSendStatus().equals(CommonSendStatus.PUBLISHED_STATUS_1)) {
                    doReleaseData(announcement.getId());
                }
                return Result.OK("添加成功!");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return Result.error("添加失败");
    }

    @Override
    public Result<String> update(UpdateAnnouncementParam param) {
        try {
            Announcement oldBean = announcementService.getById(param.getId());
            if (oldBean == null) {
                return Result.error("数据未找到!");
            }
            if (StrUtil.isNotBlank(param.getTitle()) && !param.getTitle().equals(oldBean.getTitle())) {
                param.setTitle(XSSUtils.striptXSS(param.getTitle()));
            } else {
                param.setTitle(null);
            }
            Announcement announcement = BeanUtil.toBean(param, Announcement.class);
            if (announcementService.updateAnnouncement(announcement)) {
                return Result.OK("编辑成功!");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return Result.error("编辑失败");
    }

    @Override
    public Result<String> delete(Long id) {
        try {
            if (announcementService.removeById(id)) {
                return Result.OK("删除成功!");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return Result.error("删除失败");
    }

    @Override
    public Result<String> deleteBatch(String ids) {
        try {
            List<Long> idList = Convert.toList(Long.class, ids.split(","));
            if (announcementService.removeByIds(idList)) {
                return Result.OK("批量删除成功!");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return Result.error("批量删除失败");
    }

    @Override
    public Result<AnnouncementResult> get(Long id) {
        try {
            Announcement announcement = announcementService.getById(id);
            if (announcement == null) {
                return Result.error("数据未找到!");
            }
            return Result.OK(BeanUtil.toBean(announcement, AnnouncementResult.class));
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return Result.error("获取数据失败！");
    }

    @Override
    public ModelAndView show(ModelAndView modelAndView, Long id) {
        Announcement announcement = announcementService.getById(id);
        if (announcement != null) {
            boolean tokenOK = LoginUserContext.getInstance().checkToken();
            // 判断是否传递了Token，并且Token有效，如果传了就不做查看限制，直接返回
            // 如果Token无效，就做查看限制：只能查看已发布的
            if (tokenOK || CommonConstant.ANNOUNCEMENT_SEND_STATUS_1.equals(announcement.getSendStatus())) {
                modelAndView.addObject("data", announcement);
                modelAndView.setViewName("announcement/showContent");
                return modelAndView;
            }
        }
        modelAndView.setStatus(HttpStatus.NOT_FOUND);
        return modelAndView;
    }

    @Override
    public Result<PageResult<AnnouncementResult>> page(AnnouncementQuery query) {
        Announcement announcement = BeanUtil.toBean(query, Announcement.class);
        QueryWrapper<Announcement> queryWrapper = QueryGenerator.initQueryWrapper(announcement, HttpContext.getRequestParameters());
        Page<Announcement> page = PageFactory.defaultPage();
        IPage<Announcement> pageList = announcementService.page(page, queryWrapper);
        return Result.OK(new AnnouncementWrapper(pageList).setWrapper(true).wrapPageResult());
    }

    @Override
    public Result<PageResult<AnnouncementMessageResult>> customSelectPage(AnnouncementQuery query) {
        LoginUser loginUser = LoginUserContext.getInstance().getLoginUser();
        query.setUserId(loginUser.getUsername());
        QueryWrapper<Announcement> queryWrapper = QueryGenerator.initQueryWrapper(BeanUtil.toBean(query, Announcement.class), HttpContext.getRequestParameters(), "common_announcement");
        if (StrUtil.isBlank(query.getSendStatus())) {
            queryWrapper.eq("send_status", MessageConstant.HAS_SEND);
        }
        if (StrUtil.isNotBlank(query.getBizSource()) && query.getBizSource().equals("isNoBpm")) {
            queryWrapper.and(wrapper -> {
                wrapper.ne("bus_type", "bpm").or().isNull("bus_type");
            });
        }
        Page<Announcement> page = PageFactory.defaultPage();
        if (page.orders().isEmpty()) {
            page.addOrder(OrderItem.asc("read_flag"), OrderItem.desc("send_time"));
        }
        IPage<AnnouncementMessageResult> pageList = announcementService.customSelectPage(page, query, queryWrapper);
        return Result.OK(ResultWrapperUtil.wrap(AnnouncementMessageResult.class, pageList));
    }

    @Override
    public Result<String> importExcel(MultipartHttpServletRequest request) {
        return super.importXls(request);
    }

    @Override
    public ModelAndView exportExcel(AnnouncementQuery query) {
        return super.exportXls(query, AnnouncementResult.class, "系统通告表");
    }

    @Override
    public Result<AnnouncementResult> doReleaseData(Long id) {
        Announcement announcement = announcementService.getById(id);
        if (announcement == null) {
            return Result.error("数据未找到!");
        }
        Announcement updateAnnouncement = new Announcement();
        updateAnnouncement.setId(id);
        updateAnnouncement.setSendStatus(CommonSendStatus.PUBLISHED_STATUS_1);
        updateAnnouncement.setSendTime(new Date());
        if (!announcement.getSender().equals(MessageConstant.SYSTEM_SENDER)) {
            LoginUser loginUser = LoginUserContext.getInstance().getLoginUser();
            updateAnnouncement.setSender(loginUser.getUsername());
        }
        boolean result = announcementService.updateById(updateAnnouncement);
//        boolean thirdRelease = false;
        if (result) {
            notify(announcement);
//            try {
//                thirdRelease = true;
//            } catch (Exception e) {
//                log.error("同步发送第三方APP消息失败：", e);
//            }
        }
        if (result) {
            return Result.OK("该系统通知发布成功!");
//        } else if (!thirdRelease) {
//            return Result.error("同步发送第三方APP消息失败!");
        } else {
            return Result.error("该系统通知发布失败!");
        }
    }

    @Override
    public Result<AnnouncementResult> doRevokeData(Long id) {
        Announcement announcement = announcementService.getById(id);
        if (announcement == null) {
            return Result.error("数据未找到!");
        }
        Announcement updateAnnouncement = new Announcement();
        updateAnnouncement.setId(id);
        updateAnnouncement.setSendStatus(CommonSendStatus.REVOKE_STATUS_2);
        updateAnnouncement.setCancelTime(new Date());
        boolean result = announcementService.updateById(updateAnnouncement);
        if (result) {
            notify(announcement);
            if (StrUtil.isNotBlank(announcement.getDtTaskId())) {
                log.info("撤销钉钉消息");
            }
        }
        if (result) {
            return Result.OK("该系统通知撤销成功!");
        } else {
            return Result.error("数据未找到!");
        }
    }

    /**
     * 通知webSocket刷新消息
     *
     * @param announcement 公告
     */
    private void notify(Announcement announcement) {
        if (announcement.getMsgReceiverUserType().equals(MessageConstant.MSG_RECEIVER_USER_TYPE_ALL)) {
            JSONObject obj = new JSONObject();
            obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_TOPIC);
            obj.put(WebsocketConst.MSG_ID, announcement.getId());
            obj.put(WebsocketConst.MSG_TXT, announcement.getTitle());
            if (announcement.getTenantId() == null) {
                webSocket.sendMessage(obj);
            } else {
                webSocket.pushMessage(announcement.getTenantId(), obj.toJSONString());
            }
        } else {
            // 2.插入用户通告阅读标记表记录
            String userId = announcement.getUserIds();
            String[] userIds = userId.substring(0, (userId.length() - 1)).split(",");
            JSONObject obj = new JSONObject();
            obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_USER);
            obj.put(WebsocketConst.MSG_ID, announcement.getId());
            obj.put(WebsocketConst.MSG_TXT, announcement.getTitle());
            for (String username : userIds) {
                webSocket.sendMessage(announcement.getTenantId(), username, obj);
            }
        }
    }

}
